package com.scs.application.config;

import com.scs.application.core.exceptions.BusinessException;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.RollbackRuleAttribute;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.ArrayList;
import java.util.List;

/**
 * @Description: 事务管理
 */
//@EnableTransactionManagement
@Configuration
@Aspect
@EnableTransactionManagement
public class TransactionConfig {
    private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.jianmu.service..*.*(..))";
    /**
     * 注入事务管理器
     */
    @Autowired
    private  TransactionManager transactionManager;
    /**
     * 配置事务拦截器
     */
    @Bean
    public TransactionInterceptor txAdvice() {

        RuleBasedTransactionAttribute txAttrRequired = new RuleBasedTransactionAttribute();
        txAttrRequired.setName("REQUIRED事务");
        //设置事务传播机制，默认是PROPAGATION_REQUIRED：如果当前存在事务，则加入该事务；如果当前没有事务，则创建一个新的事务
        txAttrRequired.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        //设置异常回滚为Exception  默认是RuntimeException
        List<RollbackRuleAttribute> rollbackRuleAttributes = new ArrayList<>(2);
        rollbackRuleAttributes.add(new RollbackRuleAttribute(Exception.class));
        rollbackRuleAttributes.add(new RollbackRuleAttribute(BusinessException.class));
        txAttrRequired.setRollbackRules(rollbackRuleAttributes);

        //事务管理规则，声明具备事务管理的方法名
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        //方法名规则限制，必须以下列开头才会加入事务管理当中
        source.addTransactionalMethod("del*", txAttrRequired);
        source.addTransactionalMethod("add*", txAttrRequired);
        source.addTransactionalMethod("modify*", txAttrRequired);
        source.addTransactionalMethod("insert*", txAttrRequired);
        source.addTransactionalMethod("update*", txAttrRequired);
        source.addTransactionalMethod("batch*", txAttrRequired);
        source.addTransactionalMethod("create*", txAttrRequired);
        source.addTransactionalMethod("init*", txAttrRequired);
        source.addTransactionalMethod("save*", txAttrRequired);
        source.addTransactionalMethod("saveOrUpdate*", txAttrRequired);

        return new TransactionInterceptor((PlatformTransactionManager) transactionManager, source);
    }

    /**
     * 设置切面
     */
    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }

    /**
     * 分布式事务配置 设置为LCN模式
     *
     * @param dtxLogicWeaver
     * @return
     */
//    @ConditionalOnBean(DTXLogicWeaver.class)
//    @Bean
//    public TxLcnInterceptor txLcnInterceptor(DTXLogicWeaver dtxLogicWeaver) {
//        TxLcnInterceptor txLcnInterceptor = new TxLcnInterceptor(dtxLogicWeaver);
//        Properties properties = new Properties();
//        properties.setProperty(Transactions.DTX_TYPE, Transactions.LCN);
//        properties.setProperty(Transactions.DTX_PROPAGATION, "REQUIRED");
//        txLcnInterceptor.setTransactionAttributes(properties);
//        return txLcnInterceptor;
//    }

//    @Bean
//    public BeanNameAutoProxyCreator beanNameAutoProxyCreator(ApplicationContext applicationContext) {
//        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(Service.class);
//        List<String> beanNames = Lists.newArrayList();
//        for (String beanName : beansWithAnnotation.keySet()) {
//            Object o = beansWithAnnotation.get(beanName);
//            Method[] declaredMethods = o.getClass().getDeclaredMethods();
//
//            for (Method declaredMethod : declaredMethods) {
//                beanNames.add(o.getClass().getName());
//            }
//        }
//        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
//        //需要调整优先级，分布式事务在前，本地事务在后。
//        beanNameAutoProxyCreator.setInterceptorNames( "transactionInterceptor");
//        beanNameAutoProxyCreator.setBeanNames(beanNames.toArray(new String[0]));
//        return beanNameAutoProxyCreator;
//    }

    @Bean
    public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
        return new TransactionTemplate(transactionManager);
    }
}
